<!doctype html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>MyBatis绑定异常深度解析</title>
    <link rel="stylesheet" href="https://cdn.staticfile.org/font-awesome/6.4.0/css/all.min.css">
    <link rel="stylesheet" href="https://cdn.staticfile.org/tailwindcss/2.2.19/tailwind.min.css">
    <link href="https://fonts.googleapis.com/css2?family=Noto+Serif+SC:wght@400;500;600;700&family=Noto+Sans+SC:wght@300;400;500;700&display=swap" rel="stylesheet">
    <script src="https://cdn.jsdelivr.net/npm/mermaid@latest/dist/mermaid.min.js"></script>
    <style>
        body {
            font-family: 'Noto Sans SC', Tahoma, Arial, Roboto, "Droid Sans", "Helvetica Neue", "Droid Sans Fallback", "Heiti SC", "Hiragino Sans GB", Simsun, sans-serif;
            background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
            min-height: 100vh;
        }
        
        .hero-gradient {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            position: relative;
            overflow: hidden;
        }
        
        .hero-gradient::before {
            content: '';
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background: url("data:image/svg+xml,%3Csvg width='60' height='60' viewBox='0 0 60 60' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%23ffffff' fill-opacity='0.05'%3E%3Cpath d='M36 34v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zm0-30V0h-2v4h-4v2h4v4h2V6h4V4h-4zM6 34v-4H4v4H0v2h4v4h2v-4h4v-2H6zM6 4V0H4v4H0v2h4v4h2V6h4V4H6z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E") repeat;
        }
        
        .content-card {
            background: rgba(255, 255, 255, 0.95);
            backdrop-filter: blur(10px);
            box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
            transition: all 0.3s ease;
        }
        
        .content-card:hover {
            transform: translateY(-2px);
            box-shadow: 0 25px 50px rgba(0, 0, 0, 0.15);
        }
        
        .code-block {
            background: #1e1e1e;
            color: #d4d4d4;
            border-radius: 12px;
            overflow: hidden;
            position: relative;
        }
        
        .code-header {
            background: #2d2d2d;
            padding: 8px 16px;
            font-size: 12px;
            color: #888;
            border-bottom: 1px solid #3e3e3e;
        }
        
        pre {
            margin: 0;
            padding: 16px;
            overflow-x: auto;
            font-family: 'Consolas', 'Monaco', monospace;
            font-size: 14px;
            line-height: 1.6;
        }
        
        .error-badge {
            background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
            color: white;
            padding: 4px 12px;
            border-radius: 20px;
            font-size: 12px;
            font-weight: 500;
            display: inline-block;
            animation: pulse 2s infinite;
        }
        
        @keyframes pulse {
            0% { transform: scale(1); }
            50% { transform: scale(1.05); }
            100% { transform: scale(1); }
        }
        
        .section-title {
            position: relative;
            padding-left: 20px;
        }
        
        .section-title::before {
            content: '';
            position: absolute;
            left: 0;
            top: 50%;
            transform: translateY(-50%);
            width: 4px;
            height: 24px;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            border-radius: 2px;
        }
        
        .highlight-text {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
            font-weight: 600;
        }
        
        .solution-card {
            background: linear-gradient(135deg, #f5f7fa 0%, #e9ecef 100%);
            border-left: 4px solid #667eea;
            padding: 20px;
            border-radius: 8px;
            margin: 16px 0;
            transition: all 0.3s ease;
        }
        
        .solution-card:hover {
            transform: translateX(4px);
            box-shadow: 0 4px 12px rgba(102, 126, 234, 0.2);
        }
        
        .mermaid {
            display: flex;
            justify-content: center;
            margin: 32px 0;
        }
        
        .tip-box {
            background: #fef3c7;
            border: 1px solid #f59e0b;
            border-radius: 8px;
            padding: 16px;
            margin: 16px 0;
            position: relative;
            padding-left: 48px;
        }
        
        .tip-box::before {
            content: '\f0eb';
            font-family: 'Font Awesome 6 Free';
            font-weight: 900;
            position: absolute;
            left: 16px;
            top: 50%;
            transform: translateY(-50%);
            color: #f59e0b;
            font-size: 20px;
        }
    </style>
</head>
<body>
    <!-- Hero Section -->
    <div class="hero-gradient text-white py-20 px-8">
        <div class="max-w-6xl mx-auto text-center relative z-10">
            <div class="mb-4">
                <span class="error-badge">
                    <i class="fas fa-exclamation-triangle mr-2"></i>DEBUG GUIDE
                </span>
            </div>
            <h1 class="text-5xl font-bold mb-6 leading-tight">
                MyBatis 绑定异常
                <br>
                <span class="text-3xl font-normal opacity-90">深度解析与解决方案</span>
            </h1>
            <p class="text-xl opacity-90 max-w-3xl mx-auto leading-relaxed">
                Invalid bound statement (not found) 异常是 MyBatis 开发中的常见问题。
                本文将深入剖析其产生原因，并提供全面的解决方案。
            </p>
        </div>
    </div>

    <!-- Main Content -->
    <div class="max-w-6xl mx-auto px-8 py-12">
        <!-- 前言 -->
        <div class="content-card rounded-2xl p-8 mb-8">
            <h2 class="section-title text-3xl font-bold mb-6 text-gray-800">前言</h2>
            <p class="text-lg text-gray-700 leading-relaxed mb-6">
                在 MyBatis 教学过程中，学生经常遇到一个令人困扰的 bug。这个异常看似简单，
                却涉及 MyBatis 核心的映射机制。让我们通过一个真实案例来深入理解这个问题。
            </p>
            <div class="bg-gray-100 rounded-lg p-4 overflow-hidden">
                <img src="https://cdn.nlark.com/yuque/0/2022/png/21449790/1664502713582-c6213eaa-2283-4caa-990a-92c3a11a90db.png" 
                     alt="错误截图" 
                     class="w-full rounded shadow-lg">
            </div>
        </div>

        <!-- Bug 分析 -->
        <div class="content-card rounded-2xl p-8 mb-8">
            <h2 class="section-title text-3xl font-bold mb-6 text-gray-800">
                <i class="fas fa-microscope mr-3 text-purple-600"></i>Bug 分析
            </h2>
            
            <div class="bg-red-50 border-l-4 border-red-500 p-6 mb-6 rounded-r-lg">
                <p class="text-lg font-semibold text-red-800 mb-2">
                    异常类型：<code class="bg-red-100 px-2 py-1 rounded">org.apache.ibatis.binding.BindingException</code>
                </p>
                <p class="text-gray-700">
                    异常信息：Invalid bound statement (not found): com.qf.mapper.EmpMapper.list
                </p>
            </div>

            <p class="text-lg text-gray-700 leading-relaxed mb-6 indent-8">
                这个异常明确指向了 <span class="highlight-text">Mapper 绑定</span> 的问题。
                在 MyBatis 中，我们需要将 Java 接口与 XML 配置文件进行绑定，
                这是实现代码与 SQL 分离的关键机制。
            </p>

            <!-- MyBatis 工作原理图 -->
            <div class="mermaid">
                graph LR
                    A[Mapper接口] -->|绑定| B[Mapper.xml]
                    B -->|SQL语句| C[数据库]
                    A -->|代理模式| D[代理类]
                    D -->|执行| B
                    style A fill:#667eea,stroke:#fff,color:#fff
                    style B fill:#764ba2,stroke:#fff,color:#fff
                    style C fill:#f093fb,stroke:#fff,color:#fff
                    style D fill:#4facfe,stroke:#fff,color:#fff
            </div>

            <div class="tip-box">
                <p class="text-gray-800">
                    <strong>核心概念：</strong>MyBatis 通过动态代理创建 Mapper 接口的实现类，
                    并通过 namespace 和 id 的映射关系找到对应的 SQL 语句。
                </p>
            </div>
        </div>

        <!-- 绑定机制详解 -->
        <div class="content-card rounded-2xl p-8 mb-8">
            <h2 class="section-title text-3xl font-bold mb-6 text-gray-800">
                <i class="fas fa-link mr-3 text-purple-600"></i>绑定机制详解
            </h2>

            <div class="grid md:grid-cols-2 gap-6">
                <!-- Mapper 接口 -->
                <div>
                    <h3 class="text-xl font-semibold mb-4 text-gray-800">
                        <i class="fas fa-code mr-2 text-blue-600"></i>EmpMapper 接口
                    </h3>
                    <div class="code-block">
                        <div class="code-header">
                            <i class="fas fa-file-code mr-2"></i>EmpMapper.java
                        </div>
                        <pre><code class="language-java">package com.qf.mapper;
import com.qf.core.dao.BaseDao;
import com.qf.entity.Emp;

public interface EmpMapper extends BaseDao&lt;Emp&gt; {
    public Emp selectById(Integer empno);
}</code></pre>
                    </div>
                </div>

                <!-- Mapper XML -->
                <div>
                    <h3 class="text-xl font-semibold mb-4 text-gray-800">
                        <i class="fas fa-file-alt mr-2 text-green-600"></i>EmpMapper.xml
                    </h3>
                    <div class="code-block">
                        <div class="code-header">
                            <i class="fas fa-file-code mr-2"></i>EmpMapper.xml
                        </div>
                        <pre><code class="language-xml">&lt;?xml version="1.0" encoding="UTF-8" ?&gt;
&lt;!DOCTYPE mapper
    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd"&gt;

&lt;mapper namespace="com.qf.mapper.EmpMapper"&gt;
  &lt;select id="list" resultType="emp"&gt;
    select * from t_emp
  &lt;/select&gt;
&lt;/mapper&gt;</code></pre>
                    </div>
                </div>
            </div>

            <div class="mt-8 p-6 bg-purple-50 rounded-lg">
                <h4 class="text-lg font-semibold mb-3 text-purple-800">
                    <i class="fas fa-key mr-2"></i>绑定要点
                </h4>
                <ul class="space-y-2 text-gray-700">
                    <li class="flex items-start">
                        <i class="fas fa-check-circle text-purple-600 mt-1 mr-3"></i>
                        <span><strong>namespace</strong> 必须与接口的全限定名完全一致</span>
                    </li>
                    <li class="flex items-start">
                        <i class="fas fa-check-circle text-purple-600 mt-1 mr-3"></i>
                        <span><strong>id</strong> 必须与接口中的方法名保持一致</span>
                    </li>
                    <li class="flex items-start">
                        <i class="fas fa-check-circle text-purple-600 mt-1 mr-3"></i>
                        <span>参数类型和返回类型要正确配置</span>
                    </li>
                </ul>
            </div>
        </div>

        <!-- Bug 解决方案 -->
        <div class="content-card rounded-2xl p-8 mb-8">
            <h2 class="section-title text-3xl font-bold mb-6 text-gray-800">
                <i class="fas fa-tools mr-